package cn.com.netty.zmynetty;

import cn.com.netty.nettypushmessage.server.NettyPushMessageChannelInitializer;
import cn.com.netty.nettypushmessage.server.NettyPushMessageHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class NettyMessageServer {

    private static final Logger logger = LoggerFactory.getLogger(NettyMessageServer.class);

    @Value("${server.port}")
    public Integer port;

    // 初始化
    private void init() {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    // 设置非阻塞,用它来建立新accept的连接,用于构造ServerSocketChannel的工厂类
                    .channel(NioServerSocketChannel.class)
                    .localAddress(port)
                    // 标识当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度
                    // 如果未设置或所设置的值小于1，Java将使用默认值50。
                    // 如果大于队列的最大长度，请求会被拒绝
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    // .option(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>(){
                            @Override
                            protected void initChannel(SocketChannel socketChannel) throws Exception {
                                // 设置编解码器
                                socketChannel.pipeline().addLast(new HttpServerCodec());
                                // 设置聚合器
                                socketChannel.pipeline().addLast(new HttpObjectAggregator(65536));
                                // 用于大数据流的分区传输
                                socketChannel.pipeline().addLast(new ChunkedWriteHandler());
                                //websocket支持,设置路由
                                socketChannel.pipeline().addLast(new WebSocketServerProtocolHandler("/classMessage", null, false, 65536 * 10));
                                // 自定义业务 handler
                                socketChannel.pipeline().addLast(new NettyMessageHandler());
                            }
                    });

            // 启动server,同时启动方式为同步
            Channel channel = bootstrap.bind().sync().channel();
            logger.info("MyNetty WebSocket server starts successfully: " + channel);

            // 监听关闭的channel,设置为同步方式
            channel.closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
            logger.info("MyNetty runtime error: " + e);
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            logger.info("MyNetty WebSocket server is closed.");
        }
    }

    @PostConstruct()
    public void start(){
        //需要开启一个新的线程来执行netty server 服务器
        new Thread(new Runnable() {
            @Override
            public void run() {
                init();
            }
        }).start();
    }
}
